package vista;

import java.util.ArrayList;

import modelo.Automata;
import vista.modelo.*;

import vista.interfaces.EventDispatcher;
import vista.interfaces.ReceiveEventListener;

import com.mountainreacher.automata.MainActivity;
import com.mountainreacher.automata.R;

import control.XmlManager;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.EditText;
import android.widget.Toast;
import co.edu.icesi.tv.game.Game;
import co.edu.icesi.tv.game.GameManagerView;
import co.edu.icesi.tv.game.ImageDictionary;

public class InterfazControl extends GameManagerView implements OnTouchListener, ReceiveEventListener {

	public final static long TIME_THREAD = 100;

	public static final int X_POS = 0;
	public static final int Y_POS = 1;
	public static final int X_MOVE = 2;
	public static final int Y_MOVE = 3;
	public static final int TOUCH_TIMER = 4;
	public static final int UPDATE_VIEW = 5;
	public static final int TOUCH_UP_COUNTER = 6;
	public static final int TOUCH_DOWN_COUNTER = 7;

	public static final int EDIT_NODE = 0;
	public static final int EDIT_EDGE = 1;
	public static final int CONNECT_NODES = 2;
	public static final int REFLEXIVE_RELATION = 3;
	public static final int CHANGE_LEFT_WORLD = 4;
	public static final int CHANGE_RIGHT_WORLD = 5;

	// Touch
	public int[] touch;
	private long lastTouched;

	// Requests
	private MainActivity context;

	// Seleccionador de mundo
	private int selectedGame;

	// Mundo
	private ArrayList<Automata> automatas;
	//	private Automata automata;

	// Visual
	private Tablero tablero;

	public InterfazControl(MainActivity context, ImageDictionary imageDictionary) {
		super(context, imageDictionary, TIME_THREAD);

		this.context = context;

		this.touch = new int[7];
		this.setInteractiveObjects(new Object[]{touch});
		this.setOnTouchListener(this);

		this.automatas = new ArrayList<Automata>();
		this.automatas.add(new Automata());
		this.changeToGame(0);
	}

	@Override
	public Game onCreateGame(int gameIndex) {
		selectedGame = gameIndex;
		tablero = new Tablero(this.getWidth(), this.getHeight(), getImageDictionary(), new EventDispatcher().setReceiveEventListener(this), automatas.get(gameIndex));
		return tablero;
	}

	@Override
	public boolean onTouch(View view, MotionEvent motionEvent) {

		touch[X_MOVE] = (int) motionEvent.getX();
		touch[Y_MOVE] = (int) motionEvent.getY();

		return super.onTouchEvent(motionEvent);
	}

	@Override
	public boolean onTouchEvent(MotionEvent motionEvent) {

		switch (motionEvent.getAction()) {
		case MotionEvent.ACTION_DOWN:

			touch[TOUCH_TIMER] = 1;
			//			touch[TOUCH_DOWN_COUNTER] ++;

			// Controlando que el double toque se haga sobre una misma region
			if(Geometry.distance(touch[X_POS], touch[Y_POS], motionEvent.getX(), motionEvent.getY()) > 100)
				touch[TOUCH_UP_COUNTER] = 0;

			// Redefiniendo el valor de toque
			touch[X_POS] = (int) motionEvent.getX();
			touch[Y_POS] = (int) motionEvent.getY();

			// Guardando la ultima vez que se inicio un toque
			lastTouched = System.currentTimeMillis();

			break;

		case MotionEvent.ACTION_UP:

			touch[TOUCH_TIMER] = 0;
			touch[TOUCH_UP_COUNTER] ++;

			break;
		}

		return true;
	}

	@Override
	public void managerCall() {

		// Control for touch counter
		if(System.currentTimeMillis() - lastTouched > TIME_THREAD*4 || touch[TOUCH_TIMER] > TIME_THREAD*2) {
			touch[TOUCH_UP_COUNTER] = 0;
			//			touch[TOUCH_DOWN_COUNTER] = 0;
		}

		// Control for touch timer
		if(touch[TOUCH_TIMER] > 0)
			touch[TOUCH_TIMER] += TIME_THREAD;

		// Control for update view
		if(touch[UPDATE_VIEW] > 0)
			touch[UPDATE_VIEW] --;
	}

	@Override
	public void receiveEvent(Object objects[], int code) {

		AlertDialog.Builder alert = null;

		switch (code) {
		case EDIT_NODE:

			final VNode node = (VNode)objects[0];

			alert = new AlertDialog.Builder(context);
			String hola = "";
			alert.setTitle(getResources().getString(R.string.edit_node));
			alert.setMessage(getResources().getString(R.string.change_name));
			// Set an EditText view to get user input 
			final EditText input = new EditText(context);
			input.setText(node.name);
			alert.setView(input);

			alert.setPositiveButton(getResources().getString(R.string.save), new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int whichButton) {
					if(input.getText().length() > 0)
						node.name = input.getText().toString();
				}
			});

			alert.setNegativeButton(getResources().getString(R.string.cancel), new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int whichButton) {
					// Canceled.
				}
			});

			alert.show();

			break;

		case EDIT_EDGE:

			final VEdge edge = (VEdge)objects[0];

			alert = new AlertDialog.Builder(context);
			alert.setTitle(getResources().getString(R.string.edit_edge));
			alert.setMessage(getResources().getString(R.string.set_input_word));
			// Set an EditText view to get user input 
			final EditText input2 = new EditText(context);
			input2.setText(edge.inputWordsString);
			alert.setView(input2);

			alert.setPositiveButton(getResources().getString(R.string.remove), new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int whichButton) {
					edge.tail.outgoingEdges.remove(edge);
					edge.head.incomingEdges.remove(edge);
					automatas.get(selectedGame).edges.remove(edge);
				}
			});

			alert.setNegativeButton(getResources().getString(R.string.save), new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int whichButton) {
					if(input2.getText().length() > 0)
						edge.setInputWords(input2.getText().toString());
				}
			});

			alert.show();

			break;

		case CONNECT_NODES:

			final VNode selected = (VNode)objects[0];
			final VNode toJoin = (VNode)objects[1];

			alert = new AlertDialog.Builder(context);
			alert.setTitle(getResources().getString(R.string.define_relation));
			alert.setMessage(getResources().getString(R.string.set_input_word));
			// Set an EditText view to get user input
			final EditText input3 = new EditText(context);
			alert.setView(input3);

			alert.setPositiveButton(getResources().getString(R.string.save), new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int whichButton) {
					if(input3.getText().length() > 0) {
						VEdge edge = new VEdge(input3.getText().toString(), selected, toJoin);
						//						selected.outgoingEdges.add(edge);
						//						toJoin.incomingEdges.add(edge);
						//						automatas.get(selectedGame).edges.add(edge);
						automatas.get(selectedGame).addEdge(edge);
					}
				}
			});

			alert.setNegativeButton(getResources().getString(R.string.cancel), new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int whichButton) {
					// Canceled.
				}
			});

			alert.show();

			break;

		case REFLEXIVE_RELATION:

			final VNode reflexiveNode = (VNode)objects[0];

			alert = new AlertDialog.Builder(context);
			alert.setTitle(getResources().getString(R.string.define_reflexive_relation));
			alert.setMessage(getResources().getString(R.string.set_input_word));
			// Set an EditText view to get user input
			final EditText input4 = new EditText(context);
			alert.setView(input4);

			alert.setPositiveButton(getResources().getString(R.string.save), new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int whichButton) {
					if(input4.getText().length() > 0) {
						VEdge edge = new VEdge(input4.getText().toString(), reflexiveNode, reflexiveNode);
						reflexiveNode.outgoingEdges.add(edge);
						automatas.get(selectedGame).edges.add(edge);
					}
				}
			});

			alert.setNegativeButton(getResources().getString(R.string.cancel), new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int whichButton) {
					// Canceled.
				}
			});

			alert.show();

			break;

		case CHANGE_LEFT_WORLD:
			if(selectedGame > 0) {
				selectedGame --;
				tablero.changeAutomata(automatas.get(selectedGame));
				touch[UPDATE_VIEW] = 2;
				Toast.makeText(context, getResources().getString(R.string.model_selected) + " " + (selectedGame+1), 0).show();
				tablero.moveToOrigin();
			} else
				Toast.makeText(context, getResources().getString(R.string.this_is_first_model), 0).show();
			break;

		case CHANGE_RIGHT_WORLD:
			if(selectedGame == automatas.size() - 1) {
				automatas.add(new Automata());
				Toast.makeText(context, getResources().getString(R.string.new_model_created), 0).show();
			}
			selectedGame ++;
			tablero.changeAutomata(automatas.get(selectedGame));
			touch[UPDATE_VIEW] = 2;
			Toast.makeText(context, getResources().getString(R.string.model_selected) + " " +  (selectedGame+1), 0).show();
			tablero.moveToOrigin();
			break;

		default:
			return;
		}

	}

	public void reduceFem() {
		pause();
		final int previousStates =  automatas.get(selectedGame).nodes.size();
		final ProgressDialog loadingdialog = ProgressDialog.show(context,
				getResources().getString(R.string.please_waite), getResources().getString(R.string.reducing_fem), true);
		new Thread() {
			public void run() {
				long time = System.currentTimeMillis();
				if(automatas.get(selectedGame).nodes.size() > 0 && automatas.get(selectedGame).edges.size() > 0) {
					//					automatas.set(selectedGame, automatas.get(selectedGame).reduce());
					automatas.add(selectedGame+1, automatas.get(selectedGame).reduce());
				}
				time = System.currentTimeMillis() - time;
				try {sleep(2000-time);} catch(Exception e) {}
				loadingdialog.dismiss();
			}
		}.start();

		// Escuchando cuando termine la reduccion para abrir el nuevo modelo
		loadingdialog.setOnDismissListener(new OnDismissListener() {
			@Override
			public void onDismiss(DialogInterface dialog) {
				resume();
				Toast.makeText(context, automatas.get(selectedGame).partitionString, 10).show();
				selectedGame ++;
				tablero.changeAutomata(automatas.get(selectedGame));
			}
		});
	}

	public void saveModel() {

		AlertDialog.Builder alert = new AlertDialog.Builder(context);
		alert.setTitle(getResources().getString(R.string.not_implemented));
		//		alert.setMessage(getResources().getString(R.string.save_as));
		// Set an EditText view to get user input
		//		final EditText input = new EditText(context);
		//		alert.setView(input);

		//		alert.setPositiveButton(getResources().getString(R.string.save), new DialogInterface.OnClickListener() {
		//			public void onClick(DialogInterface dialog, int whichButton) {
		//				if(input.length() > 0) {
		//					try {
		//						XmlManager.saveModel(input.getText().toString(), tablero.xWindow, tablero.yWindow);
		//					} catch (IOException e) {
		//						Toast.makeText(context, getResources().getString(R.string.error_saving_model), 0).show();
		//					}
		//				} else {
		//					Toast.makeText(context, getResources().getString(R.string.name_must_have_one_character), 0).show();
		//				}
		//			}
		//		});

		alert.setNegativeButton(getResources().getString(R.string.ok), new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int whichButton) {
				// Canceled.
			}
		});

		alert.show();

	}

	private boolean exampleLoaded;
	public void loadExample() {
		if(!exampleLoaded) {
			exampleLoaded = true;
			tablero.moveToOrigin();
			VNode nodesToAdd[] = new VNode[6];
			nodesToAdd[1] = new VNode("1", 100, 300, 40);
			nodesToAdd[2] = new VNode("2", 350, 350, 40);
			nodesToAdd[3] = new VNode("3", 200, 100, 40);
			nodesToAdd[4] = new VNode("4", 400, 550, 40);
			nodesToAdd[5] = new VNode("5", 150, 550, 40);
			nodesToAdd[5].acceptor = true;
			for (int i = 1; i < nodesToAdd.length; i++)
				automatas.get(selectedGame).nodes.add(nodesToAdd[i]);
			automatas.get(selectedGame).addEdge(new VEdge("a", nodesToAdd[1], nodesToAdd[2]));automatas.get(selectedGame).addEdge(new VEdge("b", nodesToAdd[1], nodesToAdd[3]));
			automatas.get(selectedGame).addEdge(new VEdge("a", nodesToAdd[2], nodesToAdd[2]));automatas.get(selectedGame).addEdge(new VEdge("b", nodesToAdd[2], nodesToAdd[4]));
			automatas.get(selectedGame).addEdge(new VEdge("a", nodesToAdd[3], nodesToAdd[2]));automatas.get(selectedGame).addEdge(new VEdge("b", nodesToAdd[3], nodesToAdd[3]));
			automatas.get(selectedGame).addEdge(new VEdge("a", nodesToAdd[4], nodesToAdd[2]));automatas.get(selectedGame).addEdge(new VEdge("b", nodesToAdd[4], nodesToAdd[5]));
			automatas.get(selectedGame).addEdge(new VEdge("a", nodesToAdd[5], nodesToAdd[2]));automatas.get(selectedGame).addEdge(new VEdge("b", nodesToAdd[5], nodesToAdd[1]));
		} else
			Toast.makeText(context, getResources().getString(R.string.example_already_loaded), 0).show();
	}

}
